package cn.tedu.charging.order.service.impl;

import cn.tedu.charging.common.pojo.JsonResult;
import cn.tedu.charging.common.vo.UserInfoVO;
import cn.tedu.charging.order.fenign.UserClient;
import cn.tedu.charging.order.pojo.param.OrderAddParam;
import cn.tedu.charging.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Random;


@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    /**
     * 创建订单
     * 1. 生成订单号 （生产的逻辑）
     * 2. 获取 用户信息（车辆id） (微服务架构  订单服务调用 用户服务 服务之间通信)
     * 3. 获取 服务信息（场站信息和设备信息 充电站id,运营商id...） (微服务架构  订单服务调用 设备服务 服务之间通信)
     * 4. 修改充电枪的状态 为 使用中  (微服务架构  订单服务调用 设备服务 服务之间通信)
     * 5. 给设备发送开始充电指令 （物联网 订单服务 调用 充电桩设备 服务于设备之间通信）
     * @param orderAddParam
     * @return
     */
    @Override
    public String createOrder(OrderAddParam orderAddParam) {
        log.debug("创建订单-入参:{}", orderAddParam);

        log.debug("创建订单-生成订单号");
        String orderNo = getOrderNo();
        log.debug("创建订单-生成订单号:{}", orderNo);

        Integer userId = orderAddParam.getUserId();
        log.debug("创建订单-获取用户信息-入参:{}", userId);
        UserInfoVO userInfo = getUserInfoByFeign(userId);
        log.debug("创建订单-获取用户信息-入参:{},出参:{}", userId, userInfo);
        return orderNo;
    }

    @Autowired
    private RestTemplate restTemplate;
    /**
     * 调用用户服务获取用户车辆信息
     *
     * @param userId
     * @return
     */

    private UserInfoVO getUserInfo(Integer userId) {
//        String url = "http://localhost:8080/user/info/{userId}";
        String url = getUrl();
        log.debug("通过用户服务获取用户服务接口地址-url:{}", url);
//        ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
        ParameterizedTypeReference<JsonResult<UserInfoVO>> repType = new ParameterizedTypeReference<JsonResult<UserInfoVO>>() {};
        ResponseEntity<JsonResult<UserInfoVO>> forEntity = restTemplate.exchange(url, HttpMethod.GET,null,repType,userId);
        JsonResult<UserInfoVO> body =forEntity.getBody();
        return body.getData();
    }

    @Autowired
    private UserClient userClient;

    private UserInfoVO getUserInfoByFeign(Integer userId) {
        JsonResult<UserInfoVO> userInfo = userClient.getUserInfo(userId);
        UserInfoVO data = userInfo.getData();
        return data;
    }

    private String getUrl(){
        String url1 = "http://localhost:8080/user/info/{userId}";
        String url2 = "http://localhost:8081/user/info/{userId}";
        String url3 = "http://localhost:8082/user/info/{userId}";
        String[] urls = new String[]{url1,url2,url3};
        Random random = new Random();
        int i = random.nextInt(urls.length);
        return urls[i];
    }


    /**
     * 生成订单号
     * 唯一性
     *  1 UUID 随机并且唯一
     *  2 自增的数据库主键  递增 不重复 唯一  分库分表下不能保证唯一 会重复
     *
     * 全局唯一性：不能出现重复的ID号，既然是唯一标识，这是最基本的要求。
     * 趋势递增：在MySQL InnoDB引擎中使用的是聚集索引，由于多数RDBMS使用B-tree的数据结构来存储索引数据，在主键的选择上面我们应该尽量使用有序的主键保证写入性能。
     * 单调递增：保证下一个ID一定大于上一个ID，例如事务版本号、IM增量消息、排序等特殊需求。
     * 信息安全：如果ID是连续的，恶意用户的扒取工作就非常容易做了，直接按照顺序下载指定URL即可；如果是订单号就更危险了，竞对可以直接知道我们一天的单量。所以在一些应用场景下，会需要ID无规则、不规则。
     *
     * 分布式id生成器 分布式场景下 生成唯一的id
     * 雪花算法  https://www.jianshu.com/p/1af94260664a  twitter的snowflake算法  (分布式id生成器)
     * 美团leaf https://tech.meituan.com/2017/04/21/mt-leaf.html
     *
     *
     * MVP 业务刚刚开始 先自己生成
     *
     *  100000 + 随机数  + 时间戳
     * @return
     */



    private String getOrderNo(){
        String start = "1000000";
        Random random = new Random();
        int r = random.nextInt(10000);

        long now = System.currentTimeMillis();

        return start + "-" + r + "-" + now;
    }
}
